#ifndef AST_BUILDER_TEST_GUARD
#define AST_BUILDER_TEST_GUARD

#include "cppunit\TestCase.h"
#include "cppunit\TestSuite.h"
#include "cppunit\TestCaller.h"

#include "AST_testCase_Def.h"

#include "PKB\AST\AST_XLab2.h"

#include <assert.h>
#include <string>

static class tree1 {
	/*
	procedure 1 {
1.		x = 1;
2.		if x then {
3.			x = x - 1;
			}
			else {
4.			y = x + 1;
			}
5.		while y {
6.			x = x - 1;
7.			if x then {
8.				y = x * 1;
			}
		}
9.		y = y + x;
	}
	*/
public:
	// procedure
	procNode *p1;
	procNode *p2;

	// expression
	expr *e1_const_1;
	expr *e2_const_2;
	expr *e3_var_x_3;
	expr *e4_var_y_4;
	
	expr *e7_plus;
	expr *e8_minus;
	expr *e9_times;

	// assign
	assignment_stmtNode *_asn_1;
	assignment_stmtNode *_asn_2;
	assignment_stmtNode *_asn_2_3;
	assignment_stmtNode *_asn_2_4;
	
	// call
	call_stmtNode *c_1_proc1_3;	// (1)call proc1
	// proc1 index-1
	call_stmtNode *c_2_proc2_4; // (2)call proc2
	// proc2 index-2


	// if

	// while

	//
	tree1() {
		p1 = new procNode(1);
		p2 = new procNode(2);

		e1_const_1	= new numeric_expr(1);
		e2_const_2	= new numeric_expr(2);
		e3_var_x_3	= new numeric_expr(3);
		e4_var_y_4	= new numeric_expr(4);
		
		e7_plus		= new composite_expr( OP_TYPE::OP_Plus );
		e8_minus	= new composite_expr( OP_TYPE::OP_Minus );
		e9_times	= new composite_expr( OP_TYPE::OP_Times );

		// (1)x=1
		this->_asn_1 = new assignment_stmtNode ( 1, e3_var_x_3->_expr_id, p1->getProcId() );
		this->_asn_1->setRHS ( e1_const_1 );

//		2.		if x then {
		if_stmtNode *if_1_2 = new if_stmtNode( 2, e3_var_x_3->_expr_id, p1->getProcId() );
		
//		3.		x = x - 1;
		_asn_2 = new assignment_stmtNode( 3, e3_var_x_3->_expr_id, p1->getProcId() );




	}
	AST *_ast;
};

AST_NS_LANG_SIMPLE_BEGIN

class AssignStmt_Data_Test : public CppUnit::TestFixture {
private:
	assignment_stmtNode *_asn_1_1;
	assignment_stmtNode *_asn_1_2;
	assignment_stmtNode *_asn_2_3;
	assignment_stmtNode *_asn_2_4;

	expr *e1_const_1, *e2_const_2;
	expr *e3_var_x_1, *e4_var_y_2, *e5_var_z_3, *e6_var_a_4 ;
	expr *e7_plus, *e8_minus, *e9_times;
public:
	// assignment statement
	void setUp();
	void tearDown ();
	void Test_Constructor ();
	void Test_SetAndGet ();

public:
	static CppUnit::Test *suite () {
		CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "AST_Components_Tests" );
		suiteOfTests->addTest (new CppUnit::TestCaller<AssignStmt_Data_Test>(
			"test assignment Constructor",
			&AssignStmt_Data_Test::Test_Constructor ) );
		suiteOfTests->addTest (new CppUnit::TestCaller<AssignStmt_Data_Test>(
			"test assignment LHS, RHS",
			&AssignStmt_Data_Test::Test_SetAndGet ) );

		return suiteOfTests;
	};
};

class CallStmt_Data_Test : public CppUnit::TestFixture {
private:

	call_stmtNode *c_1_proc1_3;	// (1)call proc1
	// proc1 index-1
	call_stmtNode *c_2_proc2_4; // (2)call proc2
	// proc2 index-2


public:
	void setUp ();
	void tearDown ();

	void Test_Constructor ();
	void Test_SetAndGet ();


	static CppUnit::Test *suite () {
		CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "AST_Components_Tests" );
		suiteOfTests->addTest (new CppUnit::TestCaller<CallStmt_Data_Test>(
			"test Call Constructor",
			&CallStmt_Data_Test::Test_Constructor ) );
		suiteOfTests->addTest (new CppUnit::TestCaller<CallStmt_Data_Test>(
			"test Call procedure index",
			&CallStmt_Data_Test::Test_SetAndGet ) );

		return suiteOfTests;
	};
};

class WhileStmt_Test : public CppUnit::TestFixture{
private:
	while_stmtNode *w_1_conditionVarId_1_proc_1;
	while_stmtNode *w_2_conditionVarId_1_proc_2;
	while_stmtNode *w_3_conditionVarId_2_proc_2;
	while_stmtNode *w_4_conditionVarId_3_proc_1;
public:
	void setUp ();
	void tearDown ();
	void Test_Constructor ();
	//void Test_SetAndGet ();

	static CppUnit::Test *suite () {
		CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "AST_Components_Tests" );
		suiteOfTests->addTest (new CppUnit::TestCaller<CallStmt_Data_Test>(
			"[==test While Constructor==]",
			&CallStmt_Data_Test::Test_Constructor ) );

		return suiteOfTests;
	};
};

class IfStmt_Test : public CppUnit::TestFixture{
private:
	if_stmtNode *if_1_conditionVarId_1_proc_1;
	if_stmtNode *if_2_conditionVarId_1_proc_1;
	if_stmtNode *if_3_conditionVarId_4_proc_2;
	if_stmtNode *if_4_conditionVarId_5_proc_2;
public:
	void setUp ();
	void tearDown ();

	void Test_Constructor ();
	//void Test_SetAndGet ();

	static CppUnit::Test *suite () {
		CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "AST_Components_Tests" );
		suiteOfTests->addTest (new CppUnit::TestCaller<CallStmt_Data_Test>(
			"[==test If Constructor==]",
			&CallStmt_Data_Test::Test_Constructor ) );

		return suiteOfTests;
	};
};

class AST_coreTest : public CppUnit::TestFixture {
	procNode *p_1;
	procNode *p_2;
	//
	expr *e1_const_1;
	expr *e2_const_2;
	expr *e3_var_x_1;
	expr *e4_var_y_2;
	expr *e5_var_z_3;
	expr *e6_var_a_4;
	expr *e7_plus;
	expr *e8_minus;
	expr *e9_times;

	//
	assignment_stmtNode *_asn_1_1;
	assignment_stmtNode *_asn_1_2;
	assignment_stmtNode *_asn_2_3;
	assignment_stmtNode *_asn_2_4;
	
	//
	AST *_ast;
public:
	void setUp ();
	void tearDown ();

	void Test_Constructor ();

	static CppUnit::Test *suite () {
		CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "AST_core_constructor_Tests" );
		suiteOfTests->addTest (new CppUnit::TestCaller<AST_coreTest>(
			"[==test AST core Constructor==]",
			&AST_coreTest::Test_Constructor ) );

		return suiteOfTests;
	};
};

class AST_coreTest_New_statement : public CppUnit::TestFixture { 
private:
	AST *_ast;
	procNode *p1;
	procNode *p2;

	expr *e1_const_1;
	expr *e2_const_2;
	expr *e3_var_x_3;
	expr *e4_var_y_4;
	
	expr *e7_plus;
	expr *e8_minus;
	expr *e9_times;

	// assign
	assignment_stmtNode *_asn_1;
	assignment_stmtNode *_asn_2;
	assignment_stmtNode *_asn_3;
	assignment_stmtNode *_asn_4;
	
	// call
	call_stmtNode *c_proc1;	// (1)call proc1
	// proc1 index-1
	call_stmtNode *c_proc2; // (2)call proc2
	// proc2 index-2

	// while
	while_stmtNode *w_var_x;
	while_stmtNode *w_var_y;

	// if
	if_stmtNode *if_var_x;
	if_stmtNode *if_var_y;

public:
	void setUp ();
	void tearDown ();
	void Test_Add_Get_NewStmt(  );
	
	static CppUnit::Test *suite() {
		CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "AST_Add_new_statements_Tests" );
	suiteOfTests->addTest (new CppUnit::TestCaller<AST_coreTest_New_statement> (
			"[==test AST add new statement==]",
			&AST_coreTest_New_statement::Test_Add_Get_NewStmt ) );
	return suiteOfTests;
	}
};

class AST_coreTest_Statement_AcrossProcedures : public CppUnit::TestFixture {
private:
	AST *_ast;
public:
	void setUp ();
	void tearDown ();
	void Test_Add_Get_Stmts_AcrossProcedures ();
};

AST_NS_LANG_SIMPLE_END

#endif